#!/usr/bin/python3
# -*- coding: utf-8 -*-
# coding=utf-8
# Author: BillySir
from __future__ import print_function
import sys
from rule import *
from chess_board import *
from dimension import T2D

print_process = False  # 是否打印解题（试填）过程


class SumRangeRule(Rule):
    """和的范围规则"""

    def __init__(self, expect_total_min, expect_total_max, basket: ChessBasket):
        super(SumRangeRule, self).__init__(basket)
        self._expect_total_min = expect_total_min
        self._expect_total_max = expect_total_max

    def validate(self):
        actual_total = 0
        none_cell_list: List[Cell] = []
        for cell in self.parents:
            if cell.chess is None:
                none_cell_list.append(cell)
                continue
            actual_total += cell.chess.value
        none_cell_count = len(none_cell_list)
        if none_cell_count > 0:
            # 有多个未填时，判断是否超出范围
            max_n = self._basket.get_sum_max_n(none_cell_count)
            min_n = self._basket.get_sum_min_n(none_cell_count)
            if min_n + actual_total <= self._expect_total_max and self._expect_total_min <= max_n + actual_total:
                return True
            return False
        if actual_total < self._expect_total_min or actual_total > self._expect_total_max:
            return False
        self.set_chess(actual_total)
        return True

    def can_fill(self, chess_list, parent: Cell):
        """获取可下的棋子集合与给定的chess_list的交集"""
        if parent.chess is not None:
            raise Exception("parent.chess is not None. parent.chess:" + parent.chess)

        actual_total = 0
        none_cell_list: List[Cell] = []
        for cell in self.parents:
            if cell.chess is None:
                none_cell_list.append(cell)
                continue
            actual_total += cell.chess.value
        none_cell_count = len(none_cell_list)

        assert none_cell_count >= 1, "found no empty cell in rule:" + str(self)
        # 我可填的最小值=目标最小值-已填和-可用最大N和(未填数-1(我))
        max_n_total = self._basket.get_sum_max_n(none_cell_count - 1)
        min_value = self._expect_total_min - actual_total - max_n_total
        # 我可填的最大值=目标最大值-已填和-可用最小N和(未填数-1(我))
        min_n_total = self._basket.get_sum_min_n(none_cell_count - 1)
        max_value = self._expect_total_max - actual_total - min_n_total
        # 我可填的范围
        return [chess for chess in chess_list if min_value <= chess.value <= max_value]


def run():
    """8皇后问题"""

    # 初始化棋子
    chess_list = [Chess(v, v) for v in range(2)]
    # 初始化棋盒
    chess_dist = {chess_list[0]: 56, chess_list[1]: 8}
    # print('chess_dist:' + str(chess_dist))
    basket = ChessBasket(chess_dist)

    # 初始化棋盘上的格子
    cells = [Cell(basket) for _ in range(8 * 8)]
    # 初始化规则
    total = 1
    rules1 = [RuleSum(total, basket) for _ in range(8)]
    rules2 = [RuleSum(total, basket) for _ in range(8)]
    rules3 = [SumRangeRule(0, 1, basket) for _ in range(15)]
    rules4 = [SumRangeRule(0, 1, basket) for _ in range(15)]

    # 初始化棋盘
    board = ChessBoard(cells)
    board.print_process = print_process
    board.width = 8
    board.height = 8

    T2D.board = board
    T2D.width = 8
    T2D.height = 8

    Rule.batch_bind_parents(rules1, T2D.get_cells_list("-"))    # 每一行
    Rule.batch_bind_parents(rules2, T2D.get_cells_list("|"))    # 每一列
    Rule.batch_bind_parents(rules3, T2D.get_cells_list("//"))   # 每一斜线
    Rule.batch_bind_parents(rules4, T2D.get_cells_list("\\\\")) # 每一反斜线
    # 合并全部规则为一个集合rules
    rules = []
    rules.extend(rules1)
    rules.extend(rules2)
    rules.extend(rules3)
    rules.extend(rules4)
    board.rules = rules

    # 启动求解
    board.guess()
    print("finished")
    print("guess count: %d" % basket.guess_count)
